package com.xjd.edu.toolkit.lock;

import javax.validation.constraints.NotNull;
import java.time.Duration;
import java.util.Optional;
import java.util.concurrent.Callable;

/**
 * 分布式锁执行器
 * <br><br><br>
 * <p>Example:</p>
 * <pre>{@code
 * @Autowired
 * private LockExecutor executor;
 *
 * try {
 *     executor.lock("lock:order:t0001");
 *     // TODO Logic
 * } finally {
 *     executor.unlock(key);
 * }
 *
 * if (executor.tryLock("lock:order:t0002")) {
 *     try {
 *          // TODO Logic
 *     } finally {
 *          executor.unlock(key);
 *     }
 * }
 *
 * if (executor.tryLock("lock:order:t0003", Duration.ofSeconds(1L))) {
 *     try {
 *          // TODO Logic
 *     } finally {
 *          executor.unlock(key);
 *     }
 * }
 *
 * // 无返回值（推荐）
 * executor.executeWithLock("lock:order:t0004", () -> {
 *    // TODO Logic
 * });
 *
 * // 有返回值（推荐）
 * final Optional<Order> opt = executor.executeWithTryLock("lock:order:t0005", () -> {
 *    // TODO Logic
 *    return order;
 * });
 *
 * // 无返回值（推荐）
 * executor.executeWithTryLock("lock:order:t0006", () -> {
 *    // TODO Logic
 * });
 *
 * // 有返回值（推荐）
 * final Optional<Order> opt = executor.executeWithTryLock("lock:order:t0007", () -> {
 *    // TODO Logic
 *    return order;
 * });
 *
 * }
 * </pre>
 *
 * @author wangyu
 * @created 2025/3/15 15:30
 */
public interface LockExecutor {

    /**
     * 加锁，默认30s超时，每10s会自动续期30s，必须与 #unlock(String) 结对使用
     *
     * @param key
     * @see #executeWithLock(String, Runnable)
     * @see #executeWithLock(String, Callable)
     */
    void lock(@NotNull String key);

    /**
     * 释放锁
     *
     * @param key
     */
    void unlock(@NotNull String key);

    /**
     * 尝试获取锁（不等待），取不到返回 false，取到则返回 true，超时时间与续期机制与 #lock(String) 一致，必须与 #unlock(String) 结对使用
     *
     * @param key
     * @return
     * @see #executeWithLock(String, Runnable)
     * @see #executeWithLock(String, Callable)
     */
    boolean tryLock(@NotNull String key);

    /**
     * 尝试获取锁（等待 wait 时间），取不到返回 false，取到则返回 true，超时时间与续期机制与 #lock(String) 一致，必须与 #unlock(String) 结对使用
     *
     * @param key
     * @param waitTime
     * @return
     * @throws InterruptedException
     * @see #executeWithTryLock(String, Duration, Runnable)
     * @see #executeWithTryLock(String, Duration, Callable)
     */
    boolean tryLock(@NotNull String key, @NotNull Duration waitTime) throws InterruptedException;

    /**
     * 判断是否加锁
     *
     * @param key
     * @return
     */
    boolean isLocked(@NotNull String key);

    /**
     * 带分布式锁执行器
     *
     * @param key
     * @param callable
     * @param <T>
     * @return
     * @throws Exception
     */
    <T> Optional<T> executeWithLock(@NotNull String key, @NotNull Callable<T> callable) throws Exception;

    /**
     * 带分布式锁执行器
     *
     * @param key
     * @param runnable
     * @throws Exception
     */
    void executeWithLock(@NotNull String key, @NotNull Runnable runnable) throws Exception;

    /**
     * 执行器带TryLock机制（自动续租）
     *
     * @param key
     * @param callable
     * @param <T>
     * @return
     * @throws Exception
     */
    <T> Optional<T> executeWithTryLock(@NotNull String key, @NotNull Callable<T> callable) throws Exception;

    /**
     * 执行器带TryLock机制（自动续租）
     *
     * @param key
     * @param runnable
     * @throws Exception
     */
    void executeWithTryLock(@NotNull String key, @NotNull Runnable runnable) throws Exception;

    /**
     * 执行器带TryLock机制（自动续租）
     *
     * @param key
     * @param callable
     * @param <T>
     * @return
     * @throws Exception
     */
    <T> Optional<T> executeWithTryLock(@NotNull String key, @NotNull Duration waitTime, @NotNull Callable<T> callable) throws Exception;


    /**
     * 执行器带TryLock机制（自动续租）
     *
     * @param key
     * @param waitTime
     * @param runnable
     * @throws Exception
     */
    void executeWithTryLock(@NotNull String key, @NotNull Duration waitTime, @NotNull Runnable runnable) throws Exception;

}
